#include "hdl_flash.h"

#define SPIT_FLAG_TIMEOUT         ((uint32_t)0x1000)
#define SPIT_LONG_TIMEOUT         ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))

static  uint8_t FLASH_TIMEOUT_UserCallback(uint8_t errorCode)
{
    uint8_t Err_id = 0;
    /* Block communication and all processes */
    DBG_ERR("SPI timeout!!!  errorCode = %d",errorCode);
    Err_id = errorCode;
    return Err_id;
}

uint8_t hdl_flash_spi_write(uint8_t w_data)
{
	uint32_t SPITimeout = SPIT_FLAG_TIMEOUT;
	while(SPI_I2S_GetFlagStatus(FLASH_SPI_SPIx, SPI_I2S_FLAG_TXE)==RESET)
	{
		if( (SPITimeout--)==0)
        {
            return FLASH_TIMEOUT_UserCallback(1);
        }
	}
	SPI_I2S_SendData(FLASH_SPI_SPIx,w_data);
	SPITimeout = SPIT_FLAG_TIMEOUT;
	while(SPI_I2S_GetFlagStatus(FLASH_SPI_SPIx, SPI_I2S_FLAG_RXNE)==RESET)
	{
		if( (SPITimeout--)==0)
        {
            return FLASH_TIMEOUT_UserCallback(2);
        }        
	}
	return SPI_I2S_ReceiveData(FLASH_SPI_SPIx);
}

uint8_t hdl_flash_spi_read(void)
{
	return hdl_flash_spi_write(FLASH_CMD_Dummy);
}

uint32_t hdl_flash_get_jedec_id(void)
{
	uint32_t flash_id = 0;
	FLASH_SPI_CS_LOW;
	hdl_flash_spi_write(FLASH_CMD_W25X_JedecDeviceID);
	flash_id=hdl_flash_spi_read();
	flash_id<<=0x08;
	flash_id|=hdl_flash_spi_read();
	flash_id<<=0x08;
	flash_id|=hdl_flash_spi_read();
	FLASH_SPI_CS_HIGH;
	return flash_id;
}

uint16_t hdl_flash_get_device_id(void)
{
    uint16_t Temp = 0;
    FLASH_SPI_CS_LOW;
    hdl_flash_spi_write(FLASH_CMD_W25X_ManufactDeviceID);
    hdl_flash_spi_write(FLASH_CMD_Dummy);
    hdl_flash_spi_write(FLASH_CMD_Dummy);
    hdl_flash_spi_write(0X00); 
    hdl_flash_spi_write(0XEF);
    hdl_flash_spi_write(0X17);
    Temp=hdl_flash_spi_read();
    Temp<<=0x08;
    Temp|=hdl_flash_spi_read();
    FLASH_SPI_CS_HIGH;
    return Temp;
}

void SPI_WriteEnable(void)
{
	FLASH_SPI_CS_LOW;
	hdl_flash_spi_write(FLASH_CMD_W25X_WriteEnable);
	FLASH_SPI_CS_HIGH;
}

void hdl_flash_init(void)
{
    SPI_InitTypeDef SPI_InitStuctrue;
    GPIO_InitTypeDef GPIO_InitStructure;

    FLASH_SPI_GPIO_APBxClock_FUN(FLASH_SPI_GPIO_CLK,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin = FLASH_SPI_GPIO_NSS;
    GPIO_Init(FLASH_SPI_GPIO_PORT ,&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = FLASH_SPI_GPIO_SLK;
    GPIO_Init(FLASH_SPI_GPIO_PORT ,&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = FLASH_SPI_GPIO_MOSI;
    GPIO_Init(FLASH_SPI_GPIO_PORT ,&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = FLASH_SPI_GPIO_MISO;
    GPIO_Init(FLASH_SPI_GPIO_PORT ,&GPIO_InitStructure);

    FLASH_SPI_APBxClock_FUN(FLASH_SPI_CLK,ENABLE);
	SPI_InitStuctrue.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
	SPI_InitStuctrue.SPI_CPHA = SPI_CPHA_2Edge;
	SPI_InitStuctrue.SPI_CPOL = SPI_CPOL_High;
	SPI_InitStuctrue.SPI_CRCPolynomial = 0;
	SPI_InitStuctrue.SPI_DataSize = SPI_DataSize_8b;
	SPI_InitStuctrue.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStuctrue.SPI_FirstBit = SPI_FirstBit_MSB;
	SPI_InitStuctrue.SPI_Mode = SPI_Mode_Master;
	SPI_InitStuctrue.SPI_NSS = SPI_NSS_Soft;
    SPI_Init(FLASH_SPI_SPIx,&SPI_InitStuctrue);

    SPI_Cmd(FLASH_SPI_SPIx,ENABLE);
    // hdl_flash_spi_write(FLASH_CMD_Dummy);
    hdl_flash_get_device_id();
    // if(hdl_flash_get_jedec_id() == FLASH_JEDEC_ID)
    // {
    //     DBG_MSG("flsh is w25q128\r\n");
    // }
    DBG_MSG("W25qxx Jedec is 0x%x\r\n",hdl_flash_get_jedec_id());
}



// //API declare
// void SPI_WaitForWriteEnd(void);




// //写使能


// //擦除扇区（4kb）
// void SPI_Sector_Erase(uint32_t addr)
// {
// 	//写使能
// 	SPI_WriteEnable();
// 	//通信开始
// 	FLASH_SPI_CS_LOW;
// 	hdl_flash_spi_write(W25X_SectorErase);
// 	hdl_flash_spi_write(addr>>16);
// 	hdl_flash_spi_write((addr>>8)&0xff);
// 	hdl_flash_spi_write(addr&0xff);
// 	//通信结束
// 	FLASH_SPI_CS_HIGH;
// 	//等待擦除完成
// 	SPI_WaitForWriteEnd();

// }

// //等待FLASH擦除或写操作完成
// void SPI_WaitForWriteEnd(void)
// {
// 	uint8_t Status;
// 	//通信开始
// 	FLASH_SPI_CS_LOW;
// 	hdl_flash_spi_write(W25X_ReadStatusReg);	
// 	//反复读取状态寄存器
//   do
// 	{
// 		Status=hdl_flash_spi_read();
// 	}while( (Status&0x01)==1 );
// 	//通信结束
// 	FLASH_SPI_CS_HIGH;
// }

// //读取多个字节
// void SPI_FLASH_Read(uint32_t addr,uint8_t* ReadBuff,uint16_t NumByteToRead)
// {
// 		//通信开始
// 	FLASH_SPI_CS_LOW;
// 	hdl_flash_spi_write(W25X_ReadData);
// 	hdl_flash_spi_write(addr>>16);
// 	hdl_flash_spi_write((addr>>8)&0xff);
// 	hdl_flash_spi_write(addr&0xff);
	
// 	while(NumByteToRead--)
// 	{
// 		*ReadBuff=hdl_flash_spi_read();
// 		*ReadBuff++;
// 	}
// 	//通信结束
// 	FLASH_SPI_CS_HIGH;
// }



// //页写入
// void SPI_FLASH_PageWrite(uint32_t addr,uint8_t* WriteBuff,uint16_t NumByteToWrite)
// {
// 	//写使能
// 	SPI_WriteEnable();
// 	//通信开始
// 	FLASH_SPI_CS_LOW;
// 	hdl_flash_spi_write(W25X_PageProgram);
// 	hdl_flash_spi_write(addr>>16);
// 	hdl_flash_spi_write((addr>>8)&0xff);
// 	hdl_flash_spi_write(addr&0xff);
	
// 	//写入数据不能超过256个字节
// 	if(NumByteToWrite>SPI_FLASH_PageSize)
// 	{
// 		NumByteToWrite=SPI_FLASH_PageSize;
// 	}
	
// 	while(NumByteToWrite--)
// 	{
// 		hdl_flash_spi_write(*WriteBuff);
// 		*WriteBuff++;
// 	}
// 	//通信结束
// 	FLASH_SPI_CS_HIGH;
// 	//等待写入完成
// 	SPI_WaitForWriteEnd();
// }

// //不能超过4096个字节（一个块）
// void SPI_FLASH_BufferWrite(u32 WriteAddr,u8* pBuffer, u16 NumByteToWrite)
// {
//   u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
	
// 	/*mod运算求余，若writeAddr是SPI_FLASH_PageSize整数倍，运算结果Addr值为0*/
//   Addr = WriteAddr % SPI_FLASH_PageSize;
	
// 	/*差count个数据值，刚好可以对齐到页地址*/
//   count = SPI_FLASH_PageSize - Addr;
// 	/*计算出要写多少整数页*/
//   NumOfPage =  NumByteToWrite / SPI_FLASH_PageSize;
// 	/*mod运算求余，计算出剩余不满一页的字节数*/
//   NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
	
// 	/* Addr=0,则WriteAddr 刚好按页对齐 aligned  */
//   if (Addr == 0)
//   {
// 		/* NumByteToWrite < SPI_FLASH_PageSize */
//     if (NumOfPage == 0) 
//     {
//       SPI_FLASH_PageWrite(WriteAddr,pBuffer , NumByteToWrite);
//     }
//     else /* NumByteToWrite > SPI_FLASH_PageSize */
//     { 
// 			/*先把整数页都写了*/
//       while (NumOfPage--)
//       {
//         SPI_FLASH_PageWrite(WriteAddr, pBuffer, SPI_FLASH_PageSize);
//         WriteAddr +=  SPI_FLASH_PageSize;
//         pBuffer += SPI_FLASH_PageSize;
//       }
// 			/*若有多余的不满一页的数据，把它写完*/
//       SPI_FLASH_PageWrite(WriteAddr,pBuffer, NumOfSingle);
//     }
//   }
// 	/* 若地址与 SPI_FLASH_PageSize 不对齐  */
//   else 
//   {
// 		/* NumByteToWrite < SPI_FLASH_PageSize */
//     if (NumOfPage == 0)
//     {
// 			/*当前页剩余的count个位置比NumOfSingle小，一页写不完*/
//       if (NumOfSingle > count) 
//       {
//         temp = NumOfSingle - count;
// 				/*先写满当前页*/
//         SPI_FLASH_PageWrite(WriteAddr,pBuffer , count);
				
//         WriteAddr +=  count;
//         pBuffer += count;
// 				/*再写剩余的数据*/
//         SPI_FLASH_PageWrite( WriteAddr,pBuffer, temp);
//       }
//       else /*当前页剩余的count个位置能写完NumOfSingle个数据*/
//       {
//         SPI_FLASH_PageWrite(WriteAddr,pBuffer , NumByteToWrite);
//       }
//     }
//     else /* NumByteToWrite > SPI_FLASH_PageSize */
//     {
// 			/*地址不对齐多出的count分开处理，不加入这个运算*/
//       NumByteToWrite -= count;
//       NumOfPage =  NumByteToWrite / SPI_FLASH_PageSize;
//       NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
			
// 			/* 先写完count个数据，为的是让下一次要写的地址对齐 */
//       SPI_FLASH_PageWrite(WriteAddr,pBuffer , count);
			
// 			/* 接下来就重复地址对齐的情况 */
//       WriteAddr +=  count;
//       pBuffer += count;
// 			/*把整数页都写了*/
//       while (NumOfPage--)
//       {
//         SPI_FLASH_PageWrite(WriteAddr,pBuffer, SPI_FLASH_PageSize);
//         WriteAddr +=  SPI_FLASH_PageSize;
//         pBuffer += SPI_FLASH_PageSize;
//       }
// 			/*若有多余的不满一页的数据，把它写完*/
//       if (NumOfSingle != 0)
//       {
//         SPI_FLASH_PageWrite(WriteAddr, pBuffer, NumOfSingle);
//       }
//     }
//   }
// }

// //进入掉电模式
// void SPI_Flash_PowerDown(void)
// {
// 	//通信开始
// 	FLASH_SPI_CS_LOW;
// 	hdl_flash_spi_write(W25X_PowerDown);
// 	//通信结束
// 	FLASH_SPI_CS_HIGH;
// }

// //取消掉电模式
// void SPI_Flash_WAKEUP(void)
// {
// 		//通信开始
// 	FLASH_SPI_CS_LOW;
// 	hdl_flash_spi_write(W25X_ReleasePowerDown);
// 	//通信结束
// 	FLASH_SPI_CS_HIGH;
// }	

